﻿using DimensionsHelper.Common.Contracts.Metadata;
using Style = DimensionsHelper.Common.Contracts.Metadata.Style;

namespace DimensionsHelper.Client.WinUi.ViewModels;

public partial class MetadataFieldViewModel(string name) : MetadataNamedViewModel(name, MetadataNamedObjectKind.Field)
{
    private readonly List<MetadataCategoryViewModel> _categories = [];
    private readonly List<MetadataFieldViewModel> _fields = [];

    private readonly List<MetadataPropertyViewModel> _properties = [];
    private readonly List<MetadataTemplateViewModel> _templates = [];
    private MetadataStyleViewModel? _style;

    public IEnumerable<MetadataPropertyViewModel> Properties => _properties;

    public IEnumerable<MetadataTemplateViewModel> Templates => _templates;

    public MetadataStyleViewModel Style => _style ?? new MetadataStyleViewModel();

    public IEnumerable<MetadataCategoryViewModel> Categories => _categories;


    public void SetStyle(MetadataStyleViewModel style)
    {
        _style = style;
        style.Parent = this;
    }


    public void AddProperty(MetadataPropertyViewModel property)
    {
        int index = _properties.FindIndex(p => p.Name.Equals(property.Name, StringComparison.OrdinalIgnoreCase));

        if (index >= 0)
        {
            _properties[index] = property;
        }
        else
        {
            _properties.Add(property);
        }

        property.Parent = this;
    }


    public void AddTemplate(MetadataTemplateViewModel template)
    {
        int index = _templates.FindIndex(t => t.Name.Equals(template.Name, StringComparison.OrdinalIgnoreCase));

        if (index >= 0)
        {
            _templates[index] = template;
        }
        else
        {
            _templates.Add(template);
        }

        template.Parent = this;
    }


    public void AddCategory(MetadataCategoryViewModel category)
    {
        category.Parent = this;
        _categories.Add(category);
    }


    public void AddField(MetadataFieldViewModel field)
    {
        field.Parent = this;
        _fields.Add(field);
    }


    public static MetadataFieldViewModel FromField(IField field)
    {
        MetadataFieldViewModel fieldViewModel = new(field.Name);
        // properties
        foreach (IProperty property in field.Properties)
        {
            fieldViewModel.AddProperty(new MetadataPropertyViewModel(property.Name)
            {
                Value = property.Value
            });
        }

        // templates
        foreach (ITemplate template in field.Templates)
        {
            fieldViewModel.AddTemplate(new MetadataTemplateViewModel(template.Name)
            {
                Value = template.Value
            });
        }

        // style
        if (field.Style != null)
        {
            Style? current = field.Style.Get(field.Document.Context);
            if (current != null)
            {
                fieldViewModel.SetStyle(MetadataStyleViewModel.FromMetadata(current));
            }
        }

        // elements
        foreach (IElement element in field.Elements)
        {
            fieldViewModel.AddCategory(MetadataCategoryViewModel.FromMetadata(element));
        }

        return fieldViewModel;
    }


    public static MetadataFieldViewModel FromArray(IArray array)
    {
        MetadataFieldViewModel field = FromField(array);

        foreach (IField subField in array.Class.Fields)
        {
            MetadataFieldViewModel fieldViewModel;

            if (subField is IArray subArray)
            {
                fieldViewModel = FromArray(subArray);
            }
            else
            {
                fieldViewModel = FromField(subField);
            }

            if (array.IteratorType == IteratorTypes.Categorical)
            {
                foreach (IElement element in array.Categories)
                {
                    fieldViewModel.AddChild(MetadataCategoryViewModel.FromMetadata(element));
                }
            }
            else if (array.IteratorType == IteratorTypes.NumericRanges && array.Ranges.Count > 0)
            {
                foreach (MetadataValueRange range in array.Ranges)
                {
                    int lowerBound, upperBound, step;
                    lowerBound = range.LowerBound as int? ?? 0;
                    upperBound = range.UpperBound as int? ?? 0;
                    step = range.Step as int? ?? 1;
                    for (int i = lowerBound; i <= upperBound; i += step)
                    {
                        fieldViewModel.AddChild(MetadataCategoryViewModel.FromMetadata(i));
                    }
                }
            }

            field.AddChild(fieldViewModel);
        }

        return field;
    }
}